# coding=utf-8
import json
import logging
import os
import yaml
from appium.webdriver import WebElement
from appium.webdriver.common.mobileby import By
from appium.webdriver.webdriver import WebDriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

from untils.wrapper import handle_black


class BasePage:
    _params = {}

    def __init__(self, driver: WebDriver = None):
        self.driver = driver

    @handle_black
    def find(self, locator, value: str = None):
        """
        封装find_element
        :param locator: 定位方式
        :param value: 定位方式对应的值
        :return: WebElement
        """
        element: WebElement
        # 判断:locator的类型，如果是元组就解元组
        if isinstance(locator, tuple):
            element = self.driver.find_element(*locator)
        else:
            element = self.driver.find_element(locator, value)
        return element

    def finds(self, locator, value: str = None):
        """
        封装find_elements
        :param locator: 定位方式
        :param value: 定位方式对应的值
        :return: List[WebElement]
        """
        elements: list
        if isinstance(locator, tuple):
            elements = self.driver.find_elements(*locator)
        else:
            elements = self.driver.find_elements(locator, value)
        return elements

    def wait_can_click(self, locator, time=6):
        return WebDriverWait(self.driver, time).until(expected_conditions.element_to_be_clickable(locator))

    def set_implicitly_wait(self, time):
        return self.driver.implicitly_wait(time)

    def find_and_click(self, locator, value):
        """
        封装查找元素和点击方法
        :param locator: 定位方式
        :param value: 定位方式对应的值
        """
        self.find(locator, value).click()

    def find_and_send(self, locator, value, context):
        """
        :param locator: 定位方式
        :param value: 定位方式对应的值
        :param context: 输入的内容
        """
        self.find(locator, value).send_keys(context)

    def screenshot(self):
        """
        封装截图方法
        :return:二进制数据
        """
        return self.driver.get_screenshot_as_png()

    def steps(self, yaml_path, method_name):
        """
        解析关键字，实现相应动作
        :param yaml_path: 关键字驱动的yaml文件路径
        :param method_name: PO类中的方法名
        """
        # 获取yaml文件的路径
        file = os.path.join(os.path.dirname(__file__), f"{yaml_path}")
        # 文件路径判空，不为空读取yaml文件
        if not os.path.exists(file):
            logging.error(f"No such file: {file}")
            raise FileNotFoundError(f"No such file: {file}")
        with open(file, 'r', encoding="utf-8") as f:
            fun = yaml.safe_load(f)
        steps = fun[method_name]
        # 序列化
        raw = json.dumps(steps)
        # 将_params里的key,value值以元组的形式取出来遍历
        for key, value in self._params.items():
            # 将${key}替换成value
            raw = raw.replace(f"${{{key}}}", value)
        # 反序列化
        steps = json.loads(raw)
        for step in steps:
            # 解析关键字
            if step.get('action') == "find_and_click":
                self.find_and_click(step['locator'], step['value'])
            elif step.get('action') == "find_and_send":
                self.find_and_send(step.get('locator'), step.get('value'), step.get('context'))

    def swipe_find(self, text, num=3):
        """
        根据元素text属性滑动查找元素
        :param text: 元素的text属性值
        :param num: 查找次数
        :return: WebElement
        """
        for i in range(num):
            if i == num - 1:
                self.driver.implicitly_wait(6)
                raise NoSuchElementException(f"找到{num}次， 未找到。")
            self.driver.implicitly_wait(1)
            try:
                element = self.driver.find_element(By.XPATH, f"//*[@text='{text}']")
                self.driver.implicitly_wait(6)
                return element
            except NoSuchElementException:
                logging.error("element not found,swipe up")
                size = self.driver.get_window_size()
                width = size.get('width')
                height = size.get("height")
                start_x = width / 2
                start_y = height * 0.75
                end_x = start_x
                end_y = height * 0.25
                self.driver.swipe(start_x, start_y, end_x, end_y, 1000)
